package com.dragon.cloud.zconf.curator;

import java.io.Closeable;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CuratorClient implements Closeable {

    // logger
    private static Logger logger;

    // clients
    private static ConcurrentHashMap<String, CuratorClient> clients;

    // private curator framework client . use method<getCuratorFramework> get single instance.
    private volatile CuratorFramework client = null;

    // default session zookeeper server time out number.
    private static final int DEFAULT_SESSION_TIMEOUT_MS = 60000;

    private final int sessionTimeoutMs;

    // default connect zookeeper server time out number.
    private static final int DEFAULT_CONNECTION_TIMEOUT_MS = 15000;

    // default connect zookeeper server time out number.
    private static final int DEFAULT_ZOOKEEPER_RETRY_TIMEOUT = 1000;

    // default connect zookeeper server retry time.
    private static final int DEFAULT_ZOOKEEPER_RETRY_TIME = 3;

    // zookeeper server address.
    private final String zooKeeperServers;

    static {
        logger = LoggerFactory.getLogger(CuratorClient.class);
        clients = new ConcurrentHashMap<String, CuratorClient>();
    }

    private CuratorClient(int sessionTimeoutMs, String zooKeeperServers) {
        this.sessionTimeoutMs = sessionTimeoutMs;
        this.zooKeeperServers = zooKeeperServers;
    }

    private CuratorClient(String zooKeeperServers) {
        this(DEFAULT_SESSION_TIMEOUT_MS, zooKeeperServers);
    }

    public static CuratorClient getInstance(String zooKeeperServers) {
        CuratorClient client = new CuratorClient(zooKeeperServers);
        CuratorClient existed = clients.putIfAbsent(zooKeeperServers, client);
        return (existed != null) ? existed : client;
    }

    // this will return single instance of curator framework client.
    public synchronized CuratorFramework getCuratorFramework() {
        if (null != this.client) {
            return this.client;
        } else {
            // these are reasonable arguments for the ExponentialBackoffRetry.
            // The first retry will wait 1 second - the second will wait up to 2 seconds - the
            // third will wait up to 4 seconds.
            RetryPolicy retryPolicy =
                new ExponentialBackoffRetry(DEFAULT_ZOOKEEPER_RETRY_TIMEOUT, DEFAULT_ZOOKEEPER_RETRY_TIME);

            // using the CuratorFrameworkFactory.builder() gives fine grained control
            // over creation options. See the CuratorFrameworkFactory.Builder javadoc details
            this.client = CuratorFrameworkFactory.builder().connectString(this.zooKeeperServers)
                .retryPolicy(retryPolicy)
                .connectionTimeoutMs(DEFAULT_CONNECTION_TIMEOUT_MS)
                .sessionTimeoutMs(this.sessionTimeoutMs)
                .build();

            this.client.start();
        }

        return this.client;
    }

    public void close() throws IOException {
        // if client exist.close it.
        if (null != this.client) {
            this.client.close();
            // CloseableUtils.closeQuietly(this.client);
        }
    }
}
